package gaode.com.recentlywebrtcdemo;

import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.Ack;
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.webrtc.*;
import org.webrtc.SessionDescription;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zzw on 2017/6/19.
 */

public class WebRtcClient {
    String TAG = "WebRtcClient";
    public String AUDIO_TRACK_ID = "commyaudio";
    public String VIDEO_TRACK_ID = "commyvideo";
    public String LOCAL_MEDIA_STREAM_ID = "commyvideostream";
    Socket socket;
    PeerConnectionFactory peerConnectionFactory;//工厂
    PeerConnection peerConnection;
    PCObserver observer = new PCObserver();
    SDPObserver sdpObserver = new SDPObserver();
    RemoteObserver remoteObserver = new RemoteObserver();
    IceCandidate remoteIceCandidate;
    VideoCapturerAndroid videoCapturer;
    MediaConstraints offer_sdpMediaConstraints = new MediaConstraints();//本地会话描述
    MediaConstraints answer_sdpMediaConstraints = new MediaConstraints();//本地会话描述
    VideoSource videoSource;
    VideoTrack localVideoTrack, videoTrack;

    AudioSource audioSource;
    AudioTrack localAudioTrack;
    MediaStream localMediaStream;

    RtcListener rtcListener;
    String name="androidname1";
    public interface RtcListener{
        void onStatusChanged(String newStatus);

        void onLocalStream(MediaStream localStream);

        void onAddRemoteStream(MediaStream remoteStream);

        void onRemoveRemoteStream(MediaStream remoteStream);
    }
    public WebRtcClient(String name,RtcListener listener){
        //this.name=name;
        rtcListener=listener;
        initialSystem();
        initPeerConnection();
        init();
    }
    private void init() {
        try {
            socket = IO.socket("http://192.168.0.15:3000");
            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    socket.emit("join", name);
                }
            }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.i(TAG, "连接已经断开");
                }
            }).on("sys", new Emitter.Listener() {

                @Override
                public void call(Object... args) {
                    String user = (String) args[0];
                    if (args[args.length - 1] instanceof Ack) {
                        Ack ack = (Ack) args[args.length - 1];
                        ack.call("OK");
                    } else {
                        Log.i(TAG, "args[args.length-1]");
                    }

                    if (user.equals(name)) {
                        Log.i(TAG, "user=" + user + "--Name=" + name);
                        //initPeerConnection();
                        //Log.i(TAG,"lianjieqianmiaoshu"+  peerConnection.getLocalDescription().description.toString());
                        peerConnection.createOffer(sdpObserver, offer_sdpMediaConstraints);
                    }
                }
            }).on("offer", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    if (!args[0].equals(name)) {
                        Log.i(TAG, "设置远程远程Decription" + args[1]);
                        JSONObject jsonObject = (JSONObject) JSONObject.parse((String) args[1]);
                        Log.i("sdp","offer sdp"+jsonObject.getString("sdp"));
                        //initPeerConnection();
                        peerConnection.setRemoteDescription(remoteObserver, new org.webrtc.SessionDescription(org.webrtc.SessionDescription.Type.OFFER, jsonObject.getString("sdp")));
                        //peerConnection .setRemoteDescription(remoteObserver,new SessionDescription(SessionDescription.Type.OFFER,changToDescription(jsonObject.getString("sdp"))));
                    }
                }
            }).on("answer", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    if (!args[0].equals(name)) {
                        Log.i(TAG, "要设置RemoteDescription是" + args[1]);
                        JSONObject jsonObject = (JSONObject) JSONObject.parse((String) args[1]);
                        Log.i("sdp", "sdp" + jsonObject.getString("sdp"));
                        peerConnection.setRemoteDescription(sdpObserver, new org.webrtc.SessionDescription(org.webrtc.SessionDescription.Type.ANSWER, (String) jsonObject.getString("sdp")));
                    }
                }
            }).on("candidate", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.i(TAG, "candidate方法已经回调");
                    if (!args[1].equals(name) && args[1] != null && !args[1].equals("") && !args[1].equals("null")) {
                        try {
                            Log.i(TAG, "发回的IceCandidate" + args[1]);
                            Gson g = new GsonBuilder().create();
                            IceCandidateTemp iceTemp = g.fromJson((String) args[1], IceCandidateTemp.class);
                            Log.i(TAG, "参数" + iceTemp.sdpMid + "--" + iceTemp.sdpMLineIndex + "--" + iceTemp.candidate);
                            remoteIceCandidate = new IceCandidate(iceTemp.sdpMid, iceTemp.sdpMLineIndex, iceTemp.candidate);
                            Log.i(TAG, " --当前IceCandidate-- " + g.toJson(remoteIceCandidate));
                            peerConnection.addIceCandidate(remoteIceCandidate);
                            Log.i(TAG, " --IceCandidate添加完成-- ");
                        } catch (Exception e) {
                            Log.i(TAG, "candidate err");
                        }
                    }
                }
            });
            socket.connect();
            Log.i(TAG, "监听注册完成");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
    private void initPeerConnection() {
        offer_sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        offer_sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        offer_sdpMediaConstraints.optional.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        offer_sdpMediaConstraints.optional.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        List<PeerConnection.IceServer> iceServers = new ArrayList<PeerConnection.IceServer>();
        PeerConnection.IceServer iceServer = new PeerConnection.IceServer("stun:59.110.15.178:3478", "", "");
        PeerConnection.IceServer iceServer1 = new PeerConnection.IceServer("turn:59.110.15.178:3478", "test3", "test3");
        iceServers.add(iceServer);
        iceServers.add(iceServer1);
        MediaConstraints pcConstraints = new MediaConstraints();
        pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("VoiceActivityDetection", "false"));
        peerConnection = peerConnectionFactory.createPeerConnection(iceServers, pcConstraints, observer);
        peerConnection.addStream(localMediaStream);
    }
    private void initialSystem() {
        Boolean PeerConnectionFactory_Flag = PeerConnectionFactory.initializeAndroidGlobals(rtcListener, true, true, true);
        peerConnectionFactory = new PeerConnectionFactory();
        String Name[] = CameraEnumerationAndroid.getDeviceNames();
        videoCapturer = VideoCapturerAndroid.create(Name[0], new VideoCapturerAndroid.CameraEventsHandler() {
            @Override
            public void onCameraError(String s) {

            }

            @Override
            public void onCameraFreezed(String s) {

            }

            @Override
            public void onCameraOpening(int i) {

            }

            @Override
            public void onFirstFrameAvailable() {

            }

            @Override
            public void onCameraClosed() {

            }
        });
        MediaConstraints mediaConstraints = new MediaConstraints();
        videoSource = peerConnectionFactory.createVideoSource(videoCapturer, mediaConstraints);
        localVideoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
        MediaConstraints audioConstraints = new MediaConstraints();
        audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
        localAudioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
        localMediaStream = peerConnectionFactory.createLocalMediaStream(LOCAL_MEDIA_STREAM_ID);
        localMediaStream.addTrack(localVideoTrack);
        localMediaStream.addTrack(localAudioTrack);
        rtcListener.onLocalStream(localMediaStream);
    }
    class PCObserver implements PeerConnection.Observer {
        @Override
        public void onSignalingChange(PeerConnection.SignalingState signalingState) {
            Log.i(TAG, " --onSignalingChange()-- " + signalingState);
        }

        @Override
        public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
            Log.i(TAG, " --onIceConnectionChange()-- " + iceConnectionState);
        }

        @Override
        public void onIceConnectionReceivingChange(boolean b) {
            Log.i(TAG, " --onIceConnectionReceivingChange()-- " + b);
        }

        @Override
        public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
            Log.i(TAG, " --onIceGatheringChange()-- " + iceGatheringState);

        }

        @Override
        public void onIceCandidate(IceCandidate iceCandidate) {
            Log.i(TAG, " --onIceCandidate()-- " + iceCandidate);
            remoteIceCandidate = iceCandidate;
            Gson g = new Gson();
            Log.i(TAG, "转换后的 iceCandidate：" + g.toJson(iceCandidate));
            IceCandidateTemp temp = new IceCandidateTemp(iceCandidate.sdp, iceCandidate.sdpMLineIndex, iceCandidate.sdpMid);
            socket.emit("candidate", name, g.toJson(temp));
        }

        //绑定远程流到本地数据
        @Override
        public void onAddStream(final MediaStream mediaStream) {
            Log.i(TAG, "获取远程流" + mediaStream.toString());
            rtcListener.onAddRemoteStream(mediaStream);

        }

        @Override
        public void onRemoveStream(MediaStream mediaStream) {
            Log.i(TAG, " --onRemoveStream()-- " + mediaStream);
            //mediaStream.videoTracks.get(0).dispose();
            rtcListener.onRemoveRemoteStream(mediaStream);
        }

        @Override
        public void onDataChannel(DataChannel dataChannel) {
            Log.i(TAG, " --onDataChannel()-- " + dataChannel);
        }

        @Override
        public void onRenegotiationNeeded() {
            Log.i(TAG, " --onRenegotiationNeeded()-- ");
        }
    }

    class RemoteObserver implements SdpObserver {

        @Override
        public void onCreateSuccess(org.webrtc.SessionDescription sessionDescription) {
            Log.i(TAG, "RemoteObserver 创建成功");
            Gson gson = new Gson();
            peerConnection.setLocalDescription(remoteObserver, sessionDescription);
            SessionDescriptionTemp stemp = new SessionDescriptionTemp("answer", sessionDescription.description);
            Log.i(TAG, "本地的answer发送" + sessionDescription);
            socket.emit("answer", name, gson.toJson(stemp));
        }

        @Override
        public void onSetSuccess(){
            Log.i(TAG, "RemoteObserver set成功");
            if (peerConnection.getLocalDescription() == null) {
                Log.i(TAG, "设置createAnswer");
                peerConnection.createAnswer(remoteObserver, answer_sdpMediaConstraints);
            }
        }

        @Override
        public void onCreateFailure(String s) {
            Log.i(TAG, "RemoteObserver 创建失败");
        }

        @Override
        public void onSetFailure(String s) {
            Log.i(TAG, "RemoteObserver set失败");
        }
    }

    class SDPObserver implements SdpObserver {
        @Override
        public void onCreateSuccess(SessionDescription sessionDescription) {
            Log.i(TAG, "SDPObserver 创建成功 发送请求");
            Gson gson = new Gson();
            peerConnection.setLocalDescription(sdpObserver, sessionDescription);
            SessionDescriptionTemp stemp = new SessionDescriptionTemp("offer", sessionDescription.description);
            Log.i(TAG, "本地的offer待发送" + sessionDescription.description);
            Log.i("sdp", "**offer sdp" + sessionDescription.description.toString());
            socket.emit("offer", name, gson.toJson(stemp));
        }

        @Override
        public void onSetSuccess() {
            Log.i(TAG, "SDPObserver set成功");
        }

        @Override
        public void onCreateFailure(String s) {
            Log.i(TAG, "SDPObserver 创建失败");
        }

        @Override
        public void onSetFailure(String s) {
            Log.i(TAG, "SDPObserver setFailure");
        }
    }
    /**
     * 释放资源
     */
    public void releaseAll() {
        Log.i("zzw","destoryed");
        if(peerConnection!=null){
            peerConnection.dispose();
        }
        Log.i("zzw","destoryed1");
        if (videoSource!=null){
            videoSource.dispose ();
        }
        Log.i("zzw","destoryed2");
        if (peerConnectionFactory!=null){
            peerConnectionFactory.dispose();
        }
        Log.i("zzw","destoryed3");
        if (socket!=null){
            socket.off();
            socket.disconnect();
            socket.close();
        }
        Log.i("zzw","destoryed4");

    }
}
